//普通模式的运算符表
const cOP = ['+', '-', '×', '/', '%']
//科学模式的运算符表   最后6个表示sin cos tan arcsin arccos  arctan lg ln
const sOP = ['+', '-', '×', '/', '%', '(', ')', '^', '√', '!', '@', '#', '$', '&', '_', '?', 'g', 'n']
export default {

    /**
     * 设置计算式子的公共方法
     * @param {String} pro : 要被设置的 
     */
    setProgress(pro) {
        const p = document.getElementById('progress')
        p.innerHTML = pro
    },
    /**
     * 获取计算式子
     */
    getProgress() {
        const p = document.getElementById('progress')
        return p.innerHTML.trim()
    },
    /**
     * 设置计算结果的公共方法
     * @param {String} res : 要被设置的 
     */
    setResult(res) {
        const p = document.getElementById('result')
        p.innerHTML = res
    },
    /**
     * 获取计算结果
     */
    getResult() {
        const p = document.getElementById('result')
        return p.innerHTML.trim()
    },
    /**
     * 
     * @param {×} key 
     */
    appendText(key) {
        let inner = () => {
            this.setProgress(this.getProgress() + key.innerHTML)
        }
        return inner
    },
    /**
     * 普通模式下进行计算
     * @param {String} pro 
     * @return {String} 
     */
    calcCommon(pro) {

        function isOp(c) {
            for (const it of cOP) {
                if (c === it) return true
            }
            return false
        }
        /**
         * 
         * @param {String} s1 ：前面的运算符
         * @param {String} s2 ：后面的运算符
         * @return {Boolean} ： true 前面的运算符优先级>=后面的（此时可以计算了）
         */
        function hasHigherPriority(s1, s2) {
            return !((s2 === '×' || s2 === '/' || s2 === '%') && (s1 === '+' || s1 === '-'))
        }

        /**
         * 
         * @param {Number} n1 
         * @param {Number} n2 
         * @param {String} op 
         */
        function calc(n1, n2, op) {
            switch (op) {
                case '+':
                    return n1 + n2
                case '-':
                    return n1 - n2
                case '×':
                    return n1 * n2
                case '/':
                    return n1 / n2
                case '%':
                    return n1 % n2
            }
        }

        const numStack = []
        const opStack = []
        let s = ''
        //开始计算
        for (const c of pro) {
            if (isOp(c)) {
                try {
                    //先把数解析了，放进栈里
                    const n = Number.parseFloat(s)
                    numStack.push(n)
                    s = ''
                } catch (e) {
                    console.error(e)
                    return -1
                }
                //开始比较优先级
                while (opStack.length !== 0) {
                    const bottom = opStack.pop()
                    if (hasHigherPriority(bottom, c)) {
                        //计算
                        try {
                            const n2 = numStack.pop()
                            const n1 = numStack.pop()
                            numStack.push(calc(n1, n2, bottom))
                        } catch (e) {
                            console.error(e)
                            return -1
                        }
                    } else {
                        //写回去
                        opStack.push(bottom)
                        break
                    }
                }
                opStack.push(c)

            } else {
                s += c
            }
        }

        //最后首尾还要计算一波
        if (s !== '') {
            let n2 = Number.parseInt(s)
            while (opStack.length !== 0) {
                const o = opStack.pop()
                let n1 = numStack.pop()
                n2 = calc(n1, n2, o)
            }
            numStack.push(n2)
        }

        if (numStack.length !== 1) console.error('最后数栈的元素数不是1')
        if (numStack.length === 0) {
            console.error('数栈最后为空')
            return -1
        }
        return numStack.pop()
    },
    /**
     * 科学模式下进行计算
     * @param {String} pro 
     * @return {String} 
     */
    calcSci(pro) {

        //定义单操作数运算符
        const SINGLE = ['√', '!', '@', '#', '$', '&', '_', '?', 'g', 'n']

        function isOp(c) {
            return sOP.indexOf(c) !== -1
        }
        /**
         * 
         * @param {String} s1 ：前面的运算符
         * @param {String} s2 ：后面的运算符
         * @return {Boolean} ： true 前面的运算符优先级>=后面的（此时可以计算了）
         */
        function hasHigherPriority(s1, s2) {
            
            if(s1==='(') return false
            if (SINGLE.indexOf(s1) !== -1) return true
            if (s1 === '^') return true
            return !((s2 === '×' || s2 === '/' || s2 === '%') && (s1 === '+' || s1 === '-'))
        }

        /**
         * 
         * @param {Number} n1 
         * @param {Number} n2 
         * @param {String} op 
         */
        function calcTwo(n1, n2, op) {
            switch (op) {
                case '+':
                    return n1 + n2
                case '-':
                    return n1 - n2
                case '×':
                    return n1 * n2
                case '/':
                    return n1 / n2
                case '%':
                    return n1 % n2
                case '^':
                    return Math.pow(n1, n2)
            }
        }

        /**
         * 实现阶乘
         * @param {*} n 
         */
        function fact(n) {
            let ans = 1
            for (let i = 2; i <= n; i++) {
                ans *= i
            }
            return ans
        }



        /**
         * 
         * @param {Number} n 
         * @param {String} op 
         */
        function calcOne(n, op) {
            switch (op) {
                case '@':
                    return Math.sin(n/360*2*Math.PI)
                case '#':
                    return Math.cos(n/360*2*Math.PI)
                case '$':
                    return Math.tan(n/360*2*Math.PI)
                case '&':
                    return Math.asin(n)
                case '_':
                    return Math.acos(n)
                case '?':
                    return Math.atan(n)
                case 'n':
                    return Math.log(n)
                case 'g':
                    return Math.log10(n)
                case '√':
                    return Math.sqrt(n)
                case '!':
                    return fact(n)
            }
        }

        //把多个字符的符号换成一个字符，方便处理
        function replaceOp(pro) {
            return pro.replace('√￣','√').replace('sin<sup>-1</sup>', '&').replace('cos<sup>-1</sup>', '_').replace('tan<sup>-1</sup>', '?')
                .replace('sin', '@').replace('cos', '#').replace('tan', '$').replace('lg', 'g').replace('ln', 'n')

        }

        const numStack = []
        const opStack = []
        let s = ''
        //替换里边的多字符符号
        pro = replaceOp(pro)
        //开始计算
        for (const c of pro) {
            if (isOp(c)) {
                try {
                    //先把数解析了，放进栈里
                    const n = Number.parseFloat(s)
                    if(!isNaN(n))numStack.push(n)
                    s = ''
                } catch (e) {
                    console.error(e)
                    return -1
                }
                //看看是不是右括号
                if (c === ')') {
                    let btm
                    let n1 //下 
                    let n2 //上
                    while (opStack.length !== 0&&(btm=opStack.pop())!=='(') {
                        //开始计算,直到遇到做括号
                        n2=numStack.pop()
                        //判断是否是单操作数
                        if(SINGLE.indexOf(btm)===-1){
                            n1 = numStack.pop()
                            numStack.push(calcTwo(n1,n2,btm))
                        }else{
                            numStack.push(calcOne(n2,btm))
                        }
                    }
                    continue
                }else if(c==='!'){
                    const n = numStack.pop()
                    numStack.push(calcOne(n,c))
                } 
                else if (c !== '(') {
                    //开始比较优先级
                    while (opStack.length !== 0) {
                        const bottom = opStack.pop()
                        if (hasHigherPriority(bottom, c)) {
                            //计算
                            try {
                                const n2 = numStack.pop()
                                const n1 = numStack.pop()
                                numStack.push(calcTwo(n1, n2, bottom))
                            } catch (e) {
                                console.error(e)
                                return -1
                            }
                        } else {
                            //写回去
                            opStack.push(bottom)
                            break
                        }
                    }
                }

                opStack.push(c)

            } else {
                s += c
            }
        }

        //最后首尾还要计算一波
        if (s !== '') {
            let n2 = Number.parseInt(s)
            while (opStack.length !== 0) {
                const o = opStack.pop()
                if(SINGLE.indexOf(o)===-1){
                    let n1 = numStack.pop()
                    n2 = calcTwo(n1, n2, o)
                }else{
                    n2 = calcOne(n2,o)
                }
                
            }
            numStack.push(n2)
        }

        if (numStack.length !== 1) console.error('最后数栈的元素数不是1')
        if (numStack.length === 0) {
            console.error('数栈最后为空')
            return -1
        }
        return numStack.pop()
    },


}